package org.kca.yarmour.view;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import org.kca.graphics.Displayable;
import org.kca.yarmour.data.GlobalData;
import org.kca.yarmour.data.TimeChangeListener;

public class GameTime implements Displayable
{
    private Calendar cal;
    private SimpleDateFormat sdf;
    private LinkedList<TimeUpdate> queue;
    private List<TimeChangeListener> listeners;
    private long delayTimer;
    
    public static final int GAME_HOUR = 1;
    public static final int GAME_30MIN = 2;
    public static final int GAME_15MIN = 3;
    public static final int GAME_10MIN = 4;
    public static final int GAME_5MIN = 5;
    public static final int GAME_DAY = 6;

    public GameTime()
    {
        cal = Calendar.getInstance();
        cal.set(GlobalData.GAME_START_YEAR, GlobalData.GAME_START_MONTH, GlobalData.GAME_START_DAY,
                GlobalData.GAME_START_HOUR, GlobalData.GAME_START_MIN, 0);
        sdf = new SimpleDateFormat("d/M/yyyy h:mma");
        queue = new LinkedList<TimeUpdate>();
        delayTimer = 0;
        listeners = new ArrayList<TimeChangeListener>();
    }

    public String toString()
    {
        return sdf.format(cal.getTime());
    }

    /**
     * Starts advancing game time in parallel with real time.
     * @param unit the unit to advance per interval
     * @param amount the amount of units to advance in total
     * @param interval the interval in ms between advancing each unit
     */
    public void advanceGameTime(int unit, int amount, int interval)
    {
        TimeUpdate tu = new TimeUpdate(unit, amount, interval);
        queue.offer(tu);
    }

    private void addTime(int unit, int amount)
    {
        Calendar oldTime = (Calendar)cal.clone();
        
        switch(unit)
        {
        case GAME_HOUR:
            cal.add(Calendar.HOUR, amount);
            break;
        case GAME_5MIN:
            cal.add(Calendar.MINUTE, 5 * amount);
            break;
        case GAME_10MIN:
            cal.add(Calendar.MINUTE, 10 * amount);
            break;
        case GAME_15MIN:
            cal.add(Calendar.MINUTE, 15 * amount);
            break;
        case GAME_30MIN:
            cal.add(Calendar.MINUTE, 30 * amount);
            break;
        case GAME_DAY:
            cal.add(Calendar.DAY_OF_MONTH, amount);
        default:
            break;
        }
        for (TimeChangeListener listener : listeners)
        {
            listener.timeChanged(oldTime, cal);
        }
    }
    
    /**
     * Adds a listener that listens for changes in game time
     * @param tcl the time change listener to add
     */
    public void addTimeChangeListener(TimeChangeListener tcl)
    {
        listeners.add(tcl);
    }
    
    /**
     * Gets the current time
     * @return a calendar representing the current time
     */
    public Calendar getTime()
    {
        return cal;
    }
    
    /**
     * Gets the year, month, day, hour and minute and stores in an array
     * @return the top 5 fields in the calendar time
     */
    private int[] getFields()
    {
        int[] ans = new int[5];
        ans[0] = cal.get(Calendar.YEAR);
        ans[1] = cal.get(Calendar.MONTH);
        ans[2] = cal.get(Calendar.DAY_OF_MONTH);
        ans[3] = cal.get(Calendar.HOUR);
        ans[4] = cal.get(Calendar.MINUTE);
        return ans;
    }

    @Override
    public void drawComponent(int x, int y)
    {

    }

    @Override
    public void update(long elapsedTime)
    {
        TimeUpdate tu = queue.peek();
        if (tu != null)
        {
            delayTimer += elapsedTime;
            if (delayTimer > tu.interval)
            {
                delayTimer -= tu.interval;
                tu.amount--;
                addTime(tu.unit, 1);
            }
            if (tu.amount == 0)
            {
                queue.poll();
            }
            if (queue.isEmpty())
            {
                delayTimer = 0;
            }
        }
    }

    private static class TimeUpdate
    {
        public int unit, amount, interval;

        public TimeUpdate(int unit, int amt, int interval)
        {
            this.unit = unit;
            this.amount = amt;
            this.interval = interval;
        }
    }
}
